package com.bestcem.xm.deliver.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bestcem.bp.xm.user.grpc.v1.services.Group;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.componet.sms.SmsService;
import com.bestcem.xm.deliver.entity.*;
import com.bestcem.xm.deliver.enums.MemberTypeEnum;
import com.bestcem.xm.deliver.enums.RespondentStatusEnum;
import com.bestcem.xm.deliver.enums.SmsRecordStatusEnum;
import com.bestcem.xm.deliver.grpc.client.*;
import com.bestcem.xm.deliver.grpc.client.dto.MemberDto;
import com.bestcem.xm.deliver.grpc.client.dto.OrgInfoDto;
import com.bestcem.xm.deliver.grpc.v1.services.DisturbRuleTtype;
import com.bestcem.xm.deliver.mapper.*;
import com.bestcem.xm.deliver.mq.dto.*;
import com.bestcem.xm.deliver.mq.send.biz.DeliverMessageSendService;
import com.bestcem.xm.deliver.service.DeliverDeliverService;
import com.bestcem.xm.deliver.service.DeliverDeliverSurveyDataService;
import com.bestcem.xm.deliver.service.DeliverMessageReceiverService;
import com.bestcem.xm.deliver.service.MailService;
import com.bestcem.xm.deliver.util.CommonUtil;
import com.bestcem.xm.member.grpc.v1.enums.MemberStatusEnum;
import com.google.common.collect.Lists;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

import static com.bestcem.xm.deliver.enums.DeliverScenesEnum.DELIVER_SCENES_TIMING;
import static com.bestcem.xm.deliver.enums.DeliverScenesEnum.DELIVER_SCENES_WECHATMP;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_DONE;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_FINISH;
import static com.bestcem.xm.deliver.enums.DeliverSurveyDataSurveyStatusEnum.DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER;
import static com.bestcem.xm.deliver.enums.EmailRecordStatusEnum.*;
import static com.bestcem.xm.deliver.enums.MemberDeliveryStatus.MEMBER_DELIVERY_STATUS_DISABLED;
import static com.bestcem.xm.deliver.enums.MemberSubscribeStatus.MEMBER_SUBSCRIBE_STATUS_UNSUBSCRIBE;
import static com.bestcem.xm.deliver.enums.WechatMprecordStatusEnum.WECHATMPRECORD_STATUS_DISTRUB;
import static com.bestcem.xm.deliver.enums.WechatMprecordStatusEnum.WECHATMPRECORD_STATUS_FAILED;
import static com.bestcem.xm.deliver.enums.WechatmpRecordRspdstatusEnum.WECHATMPRECORD_RSPD_STATUS_NOTSTART;
import static com.bestcem.xm.deliver.grpc.v1.services.DefaultDeliverStoreStatus.DEFAULTDELIVERSTORE_STATUS_ACTIVATE;
import static com.bestcem.xm.deliver.grpc.v1.services.DefaultDeliverStoreStatus.DEFAULTDELIVERSTORE_STATUS_DISACTIVATE;
import static com.bestcem.xm.deliver.grpc.v1.services.DefaultDeliverStoreTtype.DEFAULTDELIVERSTORE_TTYPE_STORE;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverSurveyDataSurveyStatus.*;
import static com.bestcem.xm.deliver.grpc.v1.services.EmailRecordSType.EMAILRECORD_S_TYPE_URGE;
import static com.bestcem.xm.deliver.grpc.v1.services.EmailRecordStatus.EMAILRECORD_STATUS_DISTRUB;
import static com.bestcem.xm.deliver.grpc.v1.services.SMSRecordStatus.*;
import static com.bestcem.xm.deliver.service.impl.DeliverEmailDeliverServiceImpl.P_PATTERN_EMAIL;
import static com.bestcem.xm.deliver.util.DeliverConstant.WECHATMP_SEND_STATUS_DICT;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectStatus.PROJECT_STATUS_ACTIVATED;
import static com.bestcem.xm.qdes.grpc.v1.services.ProjectStatus.PROJECT_STATUS_FINISHED;
import static com.bestcem.xm.survey.grpc.v1.services.RespondentSource.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class DeliverMessageReceiverServiceImpl implements DeliverMessageReceiverService {

    private @NonNull PushGrpcClient pushGrpcClient;
    private @NonNull MemberGrpcClient memberGrpcClient;
    private @NonNull UserGrpcClient userGrpcClient;
    private @NonNull OpenPlatformGrpcClient openPlatformGrpcClient;

    private @NonNull DeliverWechatmpRecordMapper deliverWechatmpRecordMapper;
    private @NonNull DeliverDeliverSurveyDataMapper dliverSurveyDataMapper;
    private @NonNull DeliverDeliverMapper deliverMapper;
    private @NonNull DeliverWechatmpDeliverMapper wechatmpDeliverMapper;
    private @NonNull DeliverCustomLinkMapper customLinkMapper;
    private @NonNull DeliverEmailRecordMapper emailRecordMapper;
    private @NonNull DeliverSmsRecordMapper smsRecordMapper;
    private @NonNull DeliverEmailDeliverMapper emailDeliverMapper;
    private @NonNull DeliverSmsDeliverMapper smsDeliverMapper;
    private @NonNull DeliverDisturbConfigMapper disturbConfigMapper;
    private @NonNull DeliverDisturbRuleMapper disturbRuleMapper;
    private @NonNull DeliverSurveyDeliverMapper deliverSurveyDeliverMapper;
    private @NonNull DeliverDefaultDeliverStoreMapper deliverDefaultDeliverStoreMapper;
    private @NonNull DeliverSurveyRegionMapper surveyRegionMapper;
    private @NonNull DeliverSmsBalanceMapper deliverSmsBalanceMapper;
    private @NonNull DeliverDeliverExtParamsMapper deliverExtParamsMapper;
    private @NonNull DeliverSurveyExtParamsVersionMapper deliverSurveyExtParamsVersionMapper;

    private @NonNull QdesGrpcClient qdesGrpcClient;

    private @NonNull DeliverDeliverService deliverDeliverService;
    private @NonNull RedisService redisService;
    private @NonNull DeliverDeliverSurveyDataService deliverSurveyDataService;
    private @NonNull MailService mailService;
    private @NonNull SmsService smsService;
    private @NonNull DeliverMessageSendService deliverMessageSendService;

    private static final String REGEX = "^[a-fA-F0-9]{24}$";

    @Value("#{new Boolean('${app.deliver.sms.smsNotSend}')}")
    private Boolean smsNotSend;

    @Value("${sms.smsType:push}")
    private String smsType;

    @Override
    public void executeDeliverWechatmpAsync(WechatmpDeliverMessageDto dto) {
        log.info("[deliver]微信公众号投放开始消费,消息体{}", JSONUtil.toJsonStr(dto));
        List<String> member_id_list = dto.getMemberIdlist();
        if (CollectionUtils.isEmpty(member_id_list)) {
            log.error("[deliver]微信公众号投放 executeDeliverWechatmpAsync no member_id_list");
            return;
        }

        //20221227版本号过滤，只处理最后一次修改的数据
        DeliverDeliver deliver = deliverMapper.selectById(dto.getDeliverId());
        if (Objects.isNull(deliver)) {
            log.error("[deliver]微信公众号投放 executeDeliverWechatmpAsync deliver not exist id=[{}]", dto.getDeliverId());
            return;
        }

        if (!deliver.getVersion().equals(dto.getVersion())) {
            log.warn("[deliver]微信公众号投放id=[{}] executeDeliverWechatmpAsync 本投放多次修改，只会处理最后一次的消息", dto.getDeliverId());
            return;
        }

        for (String member_id : member_id_list) {
            String code;
            MemberDto member = memberGrpcClient.getMemberById(member_id);

            Group group;
            if (Objects.nonNull(member) && StrUtil.isNotEmpty(member.getStore())) {
                group = userGrpcClient.getGroup(member.getStore());
                code = Optional.ofNullable(group).map(Group::getCode).orElseThrow(() -> new BusinessException(String.format("WeChatMPDeliver getGroup[id=%s] not found", member.getStore())));
            } else {
                log.error("[deliver]微信公众号投放 executeDeliverWechatmpAsync member 不存在");
                continue;
            }

            Map<String, String> keyMap = new HashMap<>(dto.getKwargs());
            keyMap.put("code", code);
            keyMap.put("scenes", String.valueOf(DELIVER_SCENES_WECHATMP.getValue()));
            keyMap.put("memberId", member_id);
            if (Objects.nonNull(dto.getCheckSubmit()) && dto.getCheckSubmit() > 0) {
                keyMap.put("checkSubmit", "1");
                keyMap.put("checkCode", member_id);
            } else {
                keyMap.put("checkSubmit", "0");
            }
            String link = getSurveyWechatmpDwzUrl(dto.getOrgId(), dto.getSurveyId(), dto.getDeliverId(), keyMap);

            //投放时插入字段
            String name = Optional.ofNullable(member.getName()).orElse("");
            String nickName = StrUtil.isNotEmpty(member.getNickname()) ? member.getNickname() : "";
            String openId = StrUtil.isNotEmpty(member.getOpenId()) ? member.getOpenId() : "";
            String storeName = Optional.of(group).map(Group::getName).orElse("");
            JSONObject mp_template_content = JSONObject.parseObject(dto.getMpTemplateContent());
            JSONObject template_params = new JSONObject();
            String firstVal = Optional.ofNullable(mp_template_content).map(it -> it.getJSONObject("first")).map(first -> first.getString("value")).orElse("").replace("{{联系人姓名}}", name).replace("{{联系人所属组织}}", storeName).replace("{{联系人微信昵称}}", nickName);
            String remarkVal = Optional.ofNullable(mp_template_content).map(it -> it.getJSONObject("remark")).map(remark -> remark.getString("value")).orElse("").replace("{{联系人姓名}}", name).replace("{{联系人所属组织}}", storeName).replace("{{联系人微信昵称}}", nickName);

            template_params.put("first", firstVal);
            template_params.put("remark", remarkVal);
            Optional.ofNullable(mp_template_content).map(it -> it.getJSONArray("content")).ifPresent(contentList -> {
                for (int i = 0; i < contentList.size(); i++) {
                    JSONObject content = contentList.getJSONObject(i);
                    String kal = Optional.ofNullable(content).map(cit -> cit.getString("value")).orElse("").replace("{{问卷项目名称}}", dto.getProjectName()).replace("{{联系人姓名}}", name).replace("{{联系人所属组织}}", storeName).replace("{{联系人微信昵称}}", nickName);
                    template_params.put("keyword" + (i + 1), kal);
                }
            });
            log.info("template_params:" + template_params);
            log.info("wechatmp_deliver content:" + mp_template_content);

            String msgid;
            int status;
            if (dto.getNoDisturbMemberIdlist().contains(member.getId())) {
                msgid = genDeliverMsgid(null);
                status = WECHATMPRECORD_STATUS_DISTRUB.getValue();
                link = "";
            } else {
                if (StrUtil.isEmptyIfStr(link)) {
                    msgid = genDeliverMsgid(null);
                    status = WECHATMPRECORD_STATUS_FAILED.getValue();
                } else {
                    Map<String, String> params = JSONObject.parseObject(template_params.toJSONString(), new TypeReference<Map<String, String>>() {
                    });
                    String task_number = pushGrpcClient.sendTemplateMsg(dto.getOrgId(), dto.getAppid(), openId, dto.getMpTemplateId(), link, params);
                    if (StrUtil.isEmptyIfStr(task_number)) {
                        msgid = genDeliverMsgid(null);
                        status = WECHATMPRECORD_STATUS_FAILED.getValue();
                    } else {
                        //正常发送
                        msgid = task_number;
                        Integer statusCode = pushGrpcClient.getTemplateMsgStatus(task_number);
                        log.info("模板消息id：{}模板消息发送状态：{}", task_number, code);
                        status = Objects.isNull(statusCode) ? WECHATMPRECORD_STATUS_FAILED.getValue() : WECHATMP_SEND_STATUS_DICT.get(statusCode);
                    }
                }
            }

            JSONObject watchmp_record_params = new JSONObject();
            watchmp_record_params.put("mp_deliver_id", dto.getId());
            watchmp_record_params.put("member_id", member.getId());
            watchmp_record_params.put("deliver_id", dto.getDeliverId());
            watchmp_record_params.put("content", dto.getMpTemplateContent());
            watchmp_record_params.put("appid", dto.getAppid());
            watchmp_record_params.put("openid", openId);
            watchmp_record_params.put("nickname", nickName);
            watchmp_record_params.put("username", name);
            Map<String, String> paramsmap = new HashMap<>();
            paramsmap.put("surveylink", link);
            watchmp_record_params.put("params", JSON.toJSONString(paramsmap));
            watchmp_record_params.put("msgid", msgid);
            watchmp_record_params.put("status", status);

            //可以优化成批量
            createDeliverGroupData(ListUtil.of(member_id), null, dto.getDeliverId());
            createWechatmpRecord(watchmp_record_params);
            log.info("公众号投放投放{}的记录为{}", dto.getId(), watchmp_record_params.toJSONString());
        }

        Integer msgTotal = dto.getMsgTotal();
        String lkey = "deliver:wechatmp_deliver_done_msg_count:" + dto.getDeliverId();
        Long increment = redisService.incr(lkey);
        log.info("[deliver]微信公众号投放完成消费,deliverid：{},批次：{},本次处理数量：{}", dto.getDeliverId(), increment, member_id_list.size());
        if (Objects.nonNull(increment) && increment == 1L) {
            redisService.expire(lkey, 24, TimeUnit.HOURS);
        }
        //最后消费完成的，更新状态
        if (Objects.nonNull(increment) && msgTotal == increment.intValue()) {
            LocalDateTime deliverTime = LocalDateTime.now();
            //ds_deliver_wechatmpdeliver
            DeliverWechatmpDeliver updatemp = new DeliverWechatmpDeliver();
            updatemp.setId(dto.getId());
            updatemp.setDeliverTime(deliverTime);
            //updatemp.setUpdatedId(SecurityContextHolder.getUserId());
            wechatmpDeliverMapper.updateById(updatemp);

            //修改投放状态，已投放
            DeliverDeliver update = new DeliverDeliver();
            update.setId(dto.getDeliverId());
            //update.setUpdatedId(SecurityContextHolder.getUserId());
            update.setStatus(DELIVER_STATUS_DONE.getValue());
            update.setDeliverTime(deliverTime);
            deliverMapper.updateById(update);
            log.info("[deliver]微信公众号投放全部完成消费,deliverid：{}", dto.getDeliverId());
            redisService.del(lkey);
        }
    }

    private void createWechatmpRecord(JSONObject watchmp_record_params) {
        DeliverWechatmpRecord insert = watchmp_record_params.toJavaObject(DeliverWechatmpRecord.class);
        insert.setRspdStatus(WECHATMPRECORD_RSPD_STATUS_NOTSTART.getValue());
        deliverWechatmpRecordMapper.insert(insert);
    }

    /**
     * 新增投放时需初始化相关数据
     *
     * @param member_ids
     * @param deliver_group_id
     * @param deliver_id
     */
    private void createDeliverGroupData(List<String> member_ids, String deliver_group_id, String deliver_id) {
        if (CollectionUtils.isEmpty(member_ids)) {
            return;
        }
        for (String member_id : member_ids) {
            DeliverDeliverSurveyData item = new DeliverDeliverSurveyData();
            if (StrUtil.isNotEmpty(deliver_group_id)) {
                //python 设置了upsert=True
                //这里应该查不到数据，先直接insert
                item.setDeliverGroupId(deliver_group_id);
            } else {
                //python 设置了upsert=True
                //这里应该查不到数据，先直接insert
                item.setDeliverId(deliver_id);
            }
            item.setMemberId(member_id);
            item.setUrgeNums(0);
            item.setSurveyNums(0);
            item.setSurveyStatus(DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER.getValue());
            dliverSurveyDataMapper.insert(item);
        }
    }

    private String genDeliverMsgid(String type) {
        if ("test".equals(type)) {
            return "t_" + new ObjectId().toHexString();
        }
        return "s_" + new ObjectId().toHexString();
    }

    private String getSurveyWechatmpDwzUrl(String orgId, String surveyId, String deliverId, Map<String, String> kwargs) {
        OrgInfoDto org = userGrpcClient.getOrganization(orgId);
        kwargs.put("source", String.valueOf(RESPONDENT_SOURCE_WECHATMP.getNumber()));
        JSONObject surveyLink = deliverDeliverService.getSurveyLink(orgId, surveyId, deliverId, org.getCode(), kwargs);
        String url = surveyLink.getString("url");
        String domain = surveyLink.getString("domain");
        return deliverDeliverService.getSurveyDwzLink(url, domain);
    }


    @Override
    public void executeDeliverEmailAsync(EmailDeliverMessageDto dto) {
        log.info("[deliver]邮件投放开始消费,消息体{}", JSONUtil.toJsonStr(dto));
        List<String> member_id_list = dto.getMemberIdlist();
        if (CollectionUtils.isEmpty(member_id_list)) {
            log.error("[deliver]邮件投放 executeDeliverEmailAsync no member_id_list");
            return;
        }
        DeliverDeliver deliver = deliverMapper.selectById(dto.getDeliverId());
        if (Objects.isNull(deliver)) {
            log.error("[deliver]邮件投放 executeDeliverEmailAsync deliver not exist id=[{}]", dto.getDeliverId());
            return;
        }

        if (!deliver.getVersion().equals(dto.getVersion())) {
            log.warn("[deliver]邮件投放id=[{}] executeDeliverEmailAsync 本投放多次修改，只会处理最后一次的消息", dto.getDeliverId());
            return;
        }

        String quesName = dto.getQuesName();
        String systemName = dto.getSystemName();
        String orgId = dto.getOrgId();
        Boolean flag = dto.getFlag();
        boolean checkSubmitFlag = Objects.nonNull(dto.getCheckSubmit()) && dto.getCheckSubmit() > 0;
        String projectName = dto.getProjectName();
        String mailFrom = dto.getMailFrom();
        String id = dto.getId();
        String deliverId = dto.getDeliverId();
        Integer sType = dto.getSType();
        String deliverGroupId = dto.getDeliverGroupId();

        if (dto.getSType().equals(EMAILRECORD_S_TYPE_URGE.getNumber())) {
            //催答发送处理
            for (String member_id : member_id_list) {
                MemberDto member = memberGrpcClient.getMemberById(member_id);
                Map<String, String> keyMap = new HashMap<>(dto.getKwargs());
                if (Objects.isNull(member)) {
                    log.error("[deliver]邮件投放 executeDeliverEmailAsync member_id={} 不存在", member_id);
                    continue;
                }
                Group group = null;
                String code = "";
                if (StrUtil.isNotEmpty(member.getStore())) {
                    //此处相同的store可优化成缓存
                    group = userGrpcClient.getGroup(member.getStore());
                    if (Objects.isNull(group)) {
                        log.error(String.format("EmailDeliver getGroup[id=%s] not found", member.getStore()));
                        continue;
                    }
                    code = group.getCode();
                }
                Map<String, String> newLinkDict = dto.getNewLinkDict();
                String link = newLinkDict.get(member_id);
                if (StrUtil.isEmpty(link)) {
                    link = getSurveyEmailDwzUrl(dto.getOrgId(), dto.getSurveyId(), deliverId, checkSubmitFlag, keyMap);
                }
                keyMap.put("code", code);
                keyMap.put("memberId", member_id);
                if (checkSubmitFlag) {
                    keyMap.put("checkCode", member_id);
                }
                //投放时插入字段
                String name = Optional.ofNullable(member.getName()).orElse("");
                String storeName = Optional.ofNullable(group).map(Group::getName).orElse("");
                //邮件标题替换
                String emailSubject = handleEmailSubjectAndContent(dto.getEmailSubject(), projectName, name, storeName, quesName, systemName, dto.getEmailTime(), link, false);
                //邮件取消或恢复订阅签名参数拼接链接
                //String subscribe_sig = getEmailSubscribeSig(member_id, orgId);
                String content = handleEmailSubjectAndContent(dto.getEmailTemplate(), projectName, name, storeName, quesName, systemName, dto.getEmailTime(), link, true);
                String email = member.getEmail();
                //邮件发送
                JSONObject res = sendEmail(email, emailSubject, content, mailFrom, dto.getSmtpId(), id);
                //处理邮件数据
                handleEmailData(name, email, null, content, id, member_id, deliverId, res.getInteger("status"), sType, deliverGroupId, link);
                //发送一个邮件，催答次数加一
                updateDeliverGroupData(member_id, deliverGroupId, deliverId);
            }
            return;
        }
        if (flag) {
            for (String member_id : member_id_list) {
                MemberDto member = memberGrpcClient.getMemberById(member_id);
                Map<String, String> keyMap = new HashMap<>(dto.getKwargs());
                if (Objects.isNull(member)) {
                    log.error("[deliver]短信投放 executeDeliverSmsAsync member_id={} 不存在", member_id);
                    continue;
                }
                Group group = null;
                String code = "";
                if (StrUtil.isNotEmpty(member.getStore())) {
                    //此处相同的store可优化成缓存
                    group = userGrpcClient.getGroup(member.getStore());
                    if (Objects.isNull(group)) {
                        log.error(String.format("SmsDeliver getGroup[id=%s] not found", member.getStore()));
                        continue;
                    }
                    code = group.getCode();
                }
                keyMap.put("code", code);
                keyMap.put("memberId", member_id);
                if (checkSubmitFlag) {
                    keyMap.put("checkCode", member_id);
                }
                String link = getSurveyEmailDwzUrl(dto.getOrgId(), dto.getSurveyId(), deliverId, checkSubmitFlag, keyMap);
                //投放时插入字段
                String name = Optional.ofNullable(member.getName()).orElse("");
                String storeName = Optional.ofNullable(group).map(Group::getName).orElse("");
                //邮件标题替换
                String emailSubject = handleEmailSubjectAndContent(dto.getEmailSubject(), projectName, name, storeName, quesName, systemName, dto.getEmailTime(), link, false);
                //邮件取消或恢复订阅签名参数拼接链接
                //String subscribe_sig = getEmailSubscribeSig(member_id, orgId);
                String content = handleEmailSubjectAndContent(dto.getEmailTemplate(), projectName, name, storeName, quesName, systemName, dto.getEmailTime(), link, true);
                Boolean is_blacklist = member.getMemberDeliveryStatus() == MEMBER_DELIVERY_STATUS_DISABLED.getValue();
                Boolean email_unsubscribe = member.getSubscribeStatus() == MEMBER_SUBSCRIBE_STATUS_UNSUBSCRIBE.getValue();
                //String msgid = null;
                Integer status;
                String email = member.getEmail();
                if (dto.getNoDisturbMemberIdlist().contains(member.getId())) {
                    //免打扰时不走投放 状态为免打扰拦截
                    //msgid = genDeliverMsgid(null);
                    status = EMAILRECORD_STATUS_DISTRUB.getNumber();
                    link = "";
                } else if (MemberTypeEnum.checkMemberMtype().contains(member.getMemberType()) && (is_blacklist || email_unsubscribe)) {
                    //msgid = genDeliverMsgid(null);
                    if (is_blacklist) {
                        status = EMAILRECORD_STATUS_MEMBER_BLACKLIST.getValue();
                    } else {
                        status = EMAILRECORD_STATUS_EMAIL_UNSUBSCRIBE.getValue();
                    }
                    link = "";
                } else {
                    if (StrUtil.isEmpty(link)) {
                        //没有投放链接时抛出异常并记录投放失败
                        throw new BusinessException("-1", "投放时未生成url");
                    }
                    //邮件发送
                    JSONObject res = sendEmail(email, emailSubject, content, mailFrom, dto.getSmtpId(), id);
                    //msgid = res.getString("msgid");
                    status = res.getInteger("status");
                }
                //处理邮件数据
                handleEmailData(name, email, null, content, id, member_id, deliverId, status, sType, deliverGroupId, link);
                createDeliverGroupData(ListUtil.of(member_id), deliverGroupId, deliverId);
            }
        } else {
            List<String> emailList = dto.getEmailList();
            for (String email : emailList) {
                Map<String, String> keyMap = new HashMap<>(dto.getKwargs());
                String email_hash = DigestUtils.md5Hex(email);
                keyMap.put(checkSubmitFlag ? "checkCode" : "emailhash", email_hash);
                String link = getSurveyEmailDwzUrl(dto.getOrgId(), dto.getSurveyId(), dto.getDeliverId(), checkSubmitFlag, keyMap);
                List<String> contacts = dto.getEmailContacts().get(email);
                //投放时插入字段
                String name = contacts.get(0);
                String storeName = contacts.get(1);
                //邮件标题替换
                String emailSubject = handleEmailSubjectAndContent(dto.getEmailSubject(), projectName, name, storeName, quesName, systemName, dto.getEmailTime(), link, false);
                String content = handleEmailSubjectAndContent(dto.getEmailTemplate(), projectName, name, storeName, quesName, systemName, dto.getEmailTime(), link, true);
                if (StrUtil.isEmpty(link)) {
                    //没有投放链接时抛出异常并记录投放失败
                    throw new BusinessException("-1", "投放时未生成url");
                }
                //邮件发送
                JSONObject res = sendEmail(email, emailSubject, content, mailFrom, dto.getSmtpId(), id);
                //String msgid = res.getString("msgid");
                //处理邮件数据
                handleEmailData(name, email, null, content, id, null, deliverId, res.getInteger("status"), sType, deliverGroupId, link);
                //createDeliverGroupData(ListUtil.of(member_id), deliverGroupId, deliverId);
            }
        }

        //此处没有加锁，可能会出现并发问题
        Integer msgTotal = dto.getMsgTotal();
        String lkey = "deliver:email_deliver_done_msg_count:" + dto.getDeliverId();
        Long increment = redisService.incr(lkey);
        log.info("[deliver]邮件投放完成消费,deliverid：{},批次：{},本次处理数量：{}", dto.getDeliverId(), increment, member_id_list.size());
        if (Objects.nonNull(increment) && increment == 1L) {
            redisService.expire(lkey, 24, TimeUnit.HOURS);
        }
        //最后消费完成的，更新状态
        if (Objects.nonNull(increment) && msgTotal == increment.intValue()) {
            LocalDateTime deliverTime = LocalDateTime.now();
            //ds_deliver_wechatmpdeliver
            DeliverEmailDeliver updatemp = new DeliverEmailDeliver();
            updatemp.setId(dto.getId());
            updatemp.setDeliverTime(deliverTime);
            //updatemp.setUpdatedId(SecurityContextHolder.getUserId());
            emailDeliverMapper.updateById(updatemp);

            //修改投放状态，已投放
            deliver = new DeliverDeliver();
            deliver.setId(dto.getDeliverId());
            //update.setUpdatedId(SecurityContextHolder.getUserId());
            deliver.setStatus(DELIVER_STATUS_DONE.getValue());
            deliver.setDeliverTime(deliverTime);
            deliverMapper.updateById(deliver);
            log.info("[deliver]邮件投放全部完成消费,deliverid：{}", dto.getDeliverId());
            redisService.del(lkey);
        }
    }

    private void updateDeliverGroupData(String member_id, String deliverGroupId, String deliverId) {
        LambdaQueryWrapper<DeliverDeliverSurveyData> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(deliverGroupId)) {
            queryWrapper.eq(DeliverDeliverSurveyData::getDeliverGroupId, deliverGroupId);
        } else {
            queryWrapper.eq(DeliverDeliverSurveyData::getDeliverId, deliverId);
        }
        queryWrapper.eq(DeliverDeliverSurveyData::getMemberId, member_id);
        DeliverDeliverSurveyData data = deliverSurveyDataService.getOne(queryWrapper, false);
        if (Objects.isNull(data)) {
            createDeliverGroupData(ListUtil.of(member_id), deliverGroupId, deliverId);
        }
        //催答时需将催答次数加1
        Integer urge_nums = Objects.nonNull(data.getUrgeNums()) ? data.getUrgeNums() + 1 : 1;
        data.setUrgeNums(urge_nums);
        dliverSurveyDataMapper.update(data, queryWrapper);
    }

    @Override
    public void executeSaveCustomDeliverLink(CustomDeliverLinkMessageDto msg) {
        List<DeliverCustomLink> deliverCustomLinkList = msg.getDeliverCustomLinkList();
        customLinkMapper.insertBatchSomeColumn(deliverCustomLinkList);

        Integer msgTotal = msg.getMsgTotal();
        String taskId = msg.getTaskId();

        String lkey = "deliver:savecustomdeliverlink_done_msg_count:" + taskId;
        Long increment = redisService.incr(lkey);
        if (Objects.nonNull(increment) && increment == 1L) {
            redisService.expire(lkey, 5, TimeUnit.MINUTES);
            redisService.set(taskId + ":status", "STARTED", 5, TimeUnit.MINUTES);
        }
        //最后消费完成的
        if (Objects.nonNull(increment) && msgTotal == increment.intValue()) {
            redisService.set(taskId + ":status", "SUCCESS", 5, TimeUnit.MINUTES);
            redisService.del(lkey);
        }
    }

    @Override
    public void qdesProjectCreated(CreateProjectDto msg) {
        // 当新创建项目的时候，如果勾选自动添加免打扰，则将该项目添加到免打扰中
        log.info("自动添加全局项目免打扰,DATA={}", msg);
        String surveyId = msg.getId();
        String orgId = msg.getOrgId();
        DeliverDisturbConfig disturbConfig = disturbConfigMapper.selectOne(new LambdaQueryWrapper<DeliverDisturbConfig>().eq(DeliverDisturbConfig::getOrgId,
                orgId).last("limit 1"));
        if (disturbConfig != null && disturbConfig.getAutoAddDisturb()) {
            List<DeliverDisturbRule> disRules = disturbRuleMapper.selectList(new LambdaQueryWrapper<DeliverDisturbRule>().eq(DeliverDisturbRule::getOrgId,
                    orgId).eq(DeliverDisturbRule::getTtype, DisturbRuleTtype.DISTURBRULE_TTYPE_GLOBAL.getNumber()));
            if (!CollectionUtils.isEmpty(disRules)) {
                for (DeliverDisturbRule rule : disRules) {
                    JSONArray surveyIds = new JSONArray();
                    surveyIds.add(surveyId);
                    rule.setDisturbSurveyIds(surveyIds.toJSONString());
                    disturbRuleMapper.updateById(rule);
                }
            }
        }
    }

    @Override
    public void changeDeliverStatuOnQdesDelete(DeleteProjectDto msg) {
        log.info("[deliver]项目删除消费,消息体{}", JSONUtil.toJsonStr(msg));
        // 问卷被删除时，将该问卷下所有投放置为已结束状态
        String id = msg.getId();
        String orgId = msg.getOrgId();
        if (StringUtils.isEmpty(id) || StringUtils.isEmpty(orgId)) {
            return;
        }
        List<DeliverSurveyDeliver> delivers = deliverSurveyDeliverMapper.selectList(new LambdaQueryWrapper<DeliverSurveyDeliver>()
                .eq(DeliverSurveyDeliver::getSurveyId, id).eq(DeliverSurveyDeliver::getOrgId, orgId));
        if (CollectionUtils.isEmpty(delivers)) {
            return;
        }
        List<String> deliverIds = new ArrayList<>();
        for (DeliverSurveyDeliver surveyDeliver : delivers) {
            DeliverDeliver deliver = deliverMapper.selectById(surveyDeliver.getDeliverId());
            if (deliver == null) {
                log.error("The deliver not exsit, deliver id = {}, surveyDeliver id = {}", surveyDeliver
                        .getDeliverId(), surveyDeliver.getId());
                continue;
            }
            deliver.setStatus(DELIVER_STATUS_FINISH.getValue());
            deliverMapper.updateById(deliver);
            deliverIds.add(deliver.getId());
        }
        deliverIds = deliverIds.stream().distinct().collect(Collectors.toList());
        // 删除定制化投放配置
        log.info("Now the delivers = {}", deliverIds);
        Integer deleteCount = openPlatformGrpcClient.deleteOpenCustomDeliverByDeliverId(orgId, deliverIds);
        log.info("delete count = {}", deleteCount);
    }

    @Override
    public void autoDelNoDisturbProject(DeleteProjectDto msg) {
        log.info("[deliver]删除对应的免打扰及免打扰中对应的项目,消息体{}", JSONUtil.toJsonStr(msg));
        // 删除项目时，删除对应的免打扰及免打扰中对应的项目
        String id = msg.getId();
        String orgId = msg.getOrgId();
        if (StringUtils.isEmpty(id) || StringUtils.isEmpty(orgId)) {
            return;
        }
        // 删除项目免打扰
        disturbRuleMapper.delete(new LambdaQueryWrapper<DeliverDisturbRule>()
                .eq(DeliverDisturbRule::getOrgId, orgId).eq(DeliverDisturbRule::getSurveyId, id));
        // 删除所有规则中的survey_id
        // await models.DisturbRule.update_many(
        //     [UpdateMany({'orgID': org_id}, {'$pull': {'disturb_survey_ids': survey_id}})]
        // )
        List<DeliverDisturbRule> rules = disturbRuleMapper.selectList(new LambdaQueryWrapper<DeliverDisturbRule>()
                .eq(DeliverDisturbRule::getOrgId, orgId));
        if (CollectionUtils.isEmpty(rules)) {
            return;
        }
        for (DeliverDisturbRule rule : rules) {
            String surveyIds = rule.getDisturbSurveyIds();
            if (StringUtils.isNotEmpty(surveyIds)) {
                List<String> surveyIdList = JSONArray.parseArray(surveyIds, String.class);
                if (surveyIdList.contains(id)) {
                    rule.setDisturbSurveyIds(JSONArray.toJSONString(surveyIdList.remove(id)));
                    disturbRuleMapper.updateById(rule);
                }
            }
        }
    }

    @Override
    public void deletePreChargesTask(DeleteProjectDto msg) {
        // 删除项目时删除预扣，返回预扣金额
        String id = msg.getId();
        String orgId = msg.getOrgId();
        if (StringUtils.isEmpty(id) || StringUtils.isEmpty(orgId)) {
            return;
        }
        log.info("[deliver]删除项目时删除预扣,消息体{}", JSONUtil.toJsonStr(msg));
        // 私有化不扣费
        // List<DeliverSmsDeliver> smsDelivers = smsDeliverMapper.selectList(new LambdaQueryWrapper<DeliverSmsDeliver>()
        //            .eq(DeliverSmsDeliver::getSurveyId, id).eq(DeliverSmsDeliver::getOrgId, orgId));
        //if sms_deliver:
        //await delete_pre_charge(self.session, orgID=org_id, sms_deliver_id=sms_deliver[0].oid, deliver=deliver)
    }

    @Override
    public void deliverSurveyRespondentSubmit(JSONObject data) {
        //@mq.subscribe(topics.survey_respondent_unfinish)
        //@mq.subscribe(topics.survey_respondent_submit)
        //async def deliver_survey_respondent_submit(data):
        //投放问卷收集数
        log.info("更改投放记录中的问卷状态----------{}", data.toJSONString());
        String deliver_g_id = Optional.ofNullable(data.getString("deliver_group_id")).orElse("");
        String deliver_id = Optional.ofNullable(data.getString("deliver_id")).orElse("");
        String member_id = Optional.ofNullable(data.getString("member_id")).orElse("");
        Long seq = data.getLong("seq");
        Integer status = data.getInteger("status");
        String project_id = data.getString("project_id");
        //目前没有二次投放，先注释，减少性能问题
        /*if (seq != null) {
            RespondentDto respondent = surveyGrpcClient.getRespondentBySeq(seq, project_id);
            if (respondent != null && StrUtil.isNotBlank(respondent.getAgainDeliverRecordId())) {
                status = respondent.getStatus();
                if (status.equals(RESPONDENT_STATUS_FINISH_VALUE)) {
                    DeliverAgainDeliverRecord update = new DeliverAgainDeliverRecord();
                    update.setId(respondent.getAgainDeliverRecordId());
                    update.setUpdatedDt(LocalDateTime.now());
                    update.setSurveyStatus(status);
                    deliverAgainDeliverRecordMapper.updateById(update);
                }
            }
        }*/

        String dlvr_rid = data.getString("dlvr_rid");
        if (StrUtil.isNotBlank(dlvr_rid)) {
            log.info("=== 更改wechatmprecord状态 === dlvr_rid: {}, status: {}===", dlvr_rid, status);
            DeliverWechatmpRecord update = new DeliverWechatmpRecord();
            update.setId(dlvr_rid);
            update.setUpdatedDt(LocalDateTime.now());
            update.setRspdStatus(status);
            deliverWechatmpRecordMapper.updateById(update);
        }

        if (StrUtil.isBlank(member_id)) {
            return;
        }

        JSONObject filter_params = new JSONObject();
        filter_params.put("member_id", member_id);
        if (StrUtil.isNotBlank(deliver_g_id)) {
            if (deliver_g_id.matches(REGEX)) {
                filter_params.put("deliver_group_id", deliver_g_id);
            } else {
                log.warn("非法的投放组id");
            }
        } else if (StrUtil.isNotBlank(deliver_id)) {
            if (deliver_id.matches(REGEX)) {
                filter_params.put("deliver_id", deliver_id);
            } else {
                log.warn("非法的投放id");
            }
        } else {
            return;
        }

        //python todo: !!!优化 await urge_utils.save_deliver_survey_data(session, filter_params, survey_nums, status) done by Chang
        log.info("更改投放记录中的问卷状态--filter_params过滤参数--------{}", filter_params.toJSONString());

        //默认值为打开未提交
        status = Objects.nonNull(status) ? status : DELIVERSURVEYDATA_SURVEY_STATUS_UNSUBMIT_VALUE;
        if (RespondentStatusEnum.getSubmitStatus().contains(status)) {
            status = DELIVERSURVEYDATA_SURVEY_STATUS_SUBMIT_VALUE;
        }

        //await urge_utils.save_deliver_survey_data_incr(session, filter_params, 1, status)
        saveDeliverSurveyDataIncr(filter_params, status);
        log.info("更改投放记录中的问卷状态");
    }

    /**
     * 根据过滤参数获取投放问卷的数据，更新survey_num, survey_status数据
     *
     * @param filter_params
     * @param survey_status
     */
    private void saveDeliverSurveyDataIncr(JSONObject filter_params, Integer survey_status) {
        ArrayList<Integer> deliversurveydata_survey_status_dict = Lists.newArrayList(DELIVERSURVEYDATA_SURVEY_STATUS_UNSUBMIT_VALUE, DELIVERSURVEYDATA_SURVEY_STATUS_SUBMIT_VALUE, DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER_VALUE);
        DeliverDeliverSurveyData query = filter_params.toJavaObject(DeliverDeliverSurveyData.class);
        LambdaQueryWrapper<DeliverDeliverSurveyData> queryWrap = new LambdaQueryWrapper<>(query);
        DeliverDeliverSurveyData d_s_data = deliverSurveyDataService.getOne(queryWrap);
        if (d_s_data == null) {
            d_s_data = new DeliverDeliverSurveyData();
            BeanUtil.copyProperties(query, d_s_data);
            //插入默认值
            d_s_data.setSurveyStatus(DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER.getValue());
            deliverSurveyDataService.save(d_s_data);
        }

        if (!Objects.equals(d_s_data.getSurveyStatus(), DELIVERSURVEYDATA_SURVEY_STATUS_SUBMIT_VALUE) && deliversurveydata_survey_status_dict.contains(survey_status)) {
            d_s_data.setSurveyStatus(survey_status);
        }

        //答卷删除不考虑，可以直接在原有数值上+1
        if (d_s_data.getSurveyNums() != null) {
            d_s_data.setSurveyNums(d_s_data.getSurveyNums() + 1);
        } else {
            d_s_data.setSurveyNums(1);
        }
        d_s_data.setUpdatedDt(LocalDateTime.now());
        deliverSurveyDataService.updateById(d_s_data);
    }

    @Override
    public void defaultDeliverStoreInvalidate(JSONObject msg) {
        //恢复无效的投放
        LambdaUpdateWrapper<DeliverDefaultDeliverStore> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(DeliverDefaultDeliverStore::getOrgId, msg.getString("org_id"))
                .eq(DeliverDefaultDeliverStore::getGroupId, msg.getString("id"))
                .eq(DeliverDefaultDeliverStore::getStatus, DEFAULTDELIVERSTORE_STATUS_DISACTIVATE.getNumber())
                .set(DeliverDefaultDeliverStore::getStatus, DEFAULTDELIVERSTORE_STATUS_ACTIVATE.getNumber());
        deliverDefaultDeliverStoreMapper.update(null, updateWrapper);
    }

    @Override
    public void userGroupTitleModifyList(JSONObject msg) {
        // 当用户层级title改变时，SurveyRegion中和DefaultDeliver 中的组织名称（title）需要修改
        log.info("Now to userGroupTitleModifyList, msg = {}", msg.toJSONString());
        String orgId = msg.getString("org_id");
        JSONArray titleModify = msg.getJSONArray("title_modify_list");
        if (titleModify == null) {
            log.error("The titleModify is null");
            return;
        }
        for (int i = 0; i < titleModify.size(); i++) {
            JSONObject modifyTitle = titleModify.getJSONObject(i);
            String grpId = modifyTitle.getString("grp_id");
            String oldTitle = modifyTitle.getString("old_title");
            String newTitle = modifyTitle.getString("new_title");
            userGroupTitleModify(orgId, oldTitle, newTitle);
        }
    }

    @Override
    public void userNewStoreList(JSONObject msg) {
        // 当用户层级改变, 新增门店时，分发创建对应的默认投放
        log.info("Now to userNewStoreList, msg = {}", msg.toJSONString());
        String orgId = msg.getString("org_id");
        JSONArray newstore = msg.getJSONArray("node_list");
        if (newstore == null) {
            return;
        }
        List<String> projectIds = qdesGrpcClient.getProjectIds(orgId, Arrays.asList(PROJECT_STATUS_ACTIVATED.getNumber(),
                PROJECT_STATUS_FINISHED.getNumber()));
        for (int i = 0; i < newstore.size(); i++) {
            JSONObject store = newstore.getJSONObject(i);
            String groupId = store.getString("grp_id");
            String code = store.getString("code");
            String title = store.getString("title");

            if (!CollectionUtils.isEmpty(projectIds)) {
                for (String projectId : projectIds) {
                    createDefaultStoreWithInfo(orgId, projectId, code, title, groupId);
                }
            }
        }
    }

    @Override
    public void userGroupInvalidate(JSONObject msg) {
        log.info("[deliver]失效的节点,消息体{}", msg.toJSONString());
        String orgId = msg.getString("org_id");
        List<String> idList = msg.getJSONArray("id_list").toJavaList(String.class);
        if (StringUtils.isEmpty(orgId) || CollectionUtils.isEmpty(idList)) {
            return;
        }
        // 将失效节点的投放链接设为失效状态
        deliverDefaultDeliverStoreMapper.update(null, new LambdaUpdateWrapper<DeliverDefaultDeliverStore>()
                .in(DeliverDefaultDeliverStore::getGroupId, idList)
                .eq(DeliverDefaultDeliverStore::getOrgId, orgId)
                .set(DeliverDefaultDeliverStore::getStatus, DEFAULTDELIVERSTORE_STATUS_DISACTIVATE.getNumber()));
    }

    @Override
    public void extparamUpdate(OpenplatformExtParamUpdateDto msg) {
        log.info("[deliver]同步投放外部参数表中的，外部参数描述,消息体{}", JSON.toJSONString(msg));
        deliverExtParamsMapper.update(null, new LambdaUpdateWrapper<DeliverDeliverExtParams>()
                .eq(DeliverDeliverExtParams::getExtparamId, msg.getExtParamId())
                .set(DeliverDeliverExtParams::getUpdatedDt, LocalDateTime.now())
                .set(DeliverDeliverExtParams::getExtparamDesc, msg.getDesc()));
    }

    @Override
    public void deliverSurveyExtVersionUpdate(OpenplatformExtParamUpdateDto msg) {
        log.info("[deliver]同步投放外部参数表中的，投放version,消息体{}", JSON.toJSONString(msg));
        List<DeliverDeliverExtParams> deliver_extparams = deliverExtParamsMapper.selectList(
                Wrappers.<DeliverDeliverExtParams>lambdaQuery()
                        .eq(DeliverDeliverExtParams::getExtparamId, msg.getExtParamId()));
        Set<String> survey_ids = deliver_extparams.stream().map(DeliverDeliverExtParams::getSurveyId).collect(Collectors.toSet());
        if (!ObjectUtils.isEmpty(survey_ids)) {
            LambdaUpdateWrapper<DeliverSurveyExtParamsVersion> wrapper = new LambdaUpdateWrapper<>();
            wrapper.in(DeliverSurveyExtParamsVersion::getSurveyId, survey_ids);
            wrapper.setSql("version = version + 1");
            wrapper.set(DeliverSurveyExtParamsVersion::getUpdatedDt, LocalDateTime.now());
            deliverSurveyExtParamsVersionMapper.update(null, wrapper);
        }
        //发送mq给bi
        Map<String, Object> data = new HashMap<>();
        data.put("project_id_list", survey_ids);
        deliverMessageSendService.openplatformExtParamChangedSend(data);
    }

    @Override
    public void executeDeliverSmsAsync(SmsDeliverMessageDto dto) {
        log.info("[deliver]短信投放开始消费,消息体{}", JSONUtil.toJsonStr(dto));
        List<String> member_id_list = dto.getMemberIdlist();
        if (CollectionUtils.isEmpty(member_id_list)) {
            log.error("[deliver]短信投放 executeDeliverSmsAsync no member_id_list");
            return;
        }
        DeliverDeliver deliver = deliverMapper.selectById(dto.getDeliverId());
        if (Objects.isNull(deliver)) {
            log.error("[deliver]短信投放 executeDeliverSmsAsync deliver not exist id=[{}]", dto.getDeliverId());
            return;
        }

        if (!deliver.getVersion().equals(dto.getVersion())) {
            log.warn("[deliver]短信投放id=[{}] executeDeliverSmsAsync 本投放多次修改，只会处理最后一次的消息", dto.getDeliverId());
            return;
        }
        String quesName = dto.getQuesName();
        String systemName = dto.getSystemName();
        Boolean flag = dto.getFlag();
        boolean checkSubmitFlag = Objects.nonNull(dto.getCheckSubmit()) && dto.getCheckSubmit() > 0;
        String projectName = dto.getProjectName();
        String id = dto.getId();
        String deliverId = dto.getDeliverId();
        Integer sType = dto.getSType();
        String deliverGroupId = dto.getDeliverGroupId();
        String surveyId = dto.getSurveyId();
        String orgId = dto.getOrgId();
        String sign = getSignByOrg(orgId);
        String deliverUrgeId = dto.getDeliverUrgeId();
        if (dto.getSType().equals(EMAILRECORD_S_TYPE_URGE.getNumber())) {
            //催答发送处理
            for (String member_id : member_id_list) {
                String code = "";
                MemberDto member = memberGrpcClient.getMemberById(member_id);
                Group group = null;
                if (Objects.nonNull(member)) {
                    //老数据的软删除
                    if (member.getStatus().equals(MemberStatusEnum.MemberStatus.SOFT_DELETE_VALUE)) {
                        continue;
                    }
                    if (StrUtil.isNotEmpty(member.getStore())) {
                        //此处相同的store可优化成缓存
                        group = userGrpcClient.getGroup(member.getStore());
                        if (Objects.isNull(group)) {
                            log.error(String.format("SmsDeliver getGroup[id=%s] not found", member.getStore()));
                            continue;
                        }
                        code = group.getCode();
                    }
                } else {
                    log.error("[deliver]短信投放 executeDeliverSmsAsync member_id={} 不存在", member_id);
                    continue;
                }
                Map<String, String> keyMap = new HashMap<>(dto.getKwargs());
                keyMap.put("code", code);
                keyMap.put("memberId", member_id);
                if (checkSubmitFlag) {
                    keyMap.put("checkCode", member_id);
                }
                Map<String, String> newLinkDict = dto.getNewLinkDict();
                String link = newLinkDict.get(member_id);
                if (StrUtil.isEmpty(link)) {
                    link = getSurveySmsDwzUrl(dto.getOrgId(), dto.getSurveyId(), deliverId, checkSubmitFlag, keyMap);
                }
                //投放时插入字段
                String name = Optional.ofNullable(member.getName()).orElse("");
                if (name.length() > 8) {
                    name = name.substring(0, 8);
                }
                String storeName = Optional.ofNullable(group).map(Group::getName).orElse("");
                if (storeName.length() > 10) {
                    storeName = storeName.substring(0, 10);
                }
                //替换模板内容, 需要替换字段,问卷名称10,项目名称10,系统名称：取个性化设置中的系统名称15,联系人姓名8,联系人所属组织10,问卷链接 28
                String content = handleSmsContent(dto.getTemplate(), projectName, name, storeName, quesName, systemName, link);

                if (StringUtils.isEmpty(sign)) {
                    sign = "【倍市得CEM】";
                }
                //HONDA临时修改, 要删除（来自py的注释）
                //if (DeliverConstant.HONDA_PIDS.contains(surveyId)) {
                //    continue;
                //}
                int status;
                int length;
                double balance;
                try {
                    //发送短信
                    //Map<String, Object> keywards = new HashMap<>();
                    //if (StrUtil.equals("push", smsType)) {
                    //    keywards.put("component_code", getSmsHelper(orgId));
                    //    keywards.put("sign", sign);
                    //}
                    Map<String, Object> res = smsService.sendSms(member.getMobile(), content, null);
                    length = (Integer) Optional.ofNullable(res.get("length")).orElse(0);
                    balance = (Double) Optional.ofNullable(res.get("balance")).orElse(0.0);
                    if (!ObjectUtils.isEmpty(res.get("content"))) {
                        content = (String) res.get("content");
                    }
                    //msgid = (String) res.getOrDefault("msg_id", "");
                    status = SMSRECORD_STATUS_SUCCESS.getNumber();
                } catch (Exception e) {
                    //发送异常时添加记录发送失败
                    status = SMSRECORD_STATUS_FAILED.getNumber();
                    //msgid = genDeliverMsgid(null);
                    length = 1;
                    balance = 0.0;
                    log.error("短信[{}]发送失败", member.getMobile(), e);
                    addSmsUrgeRecord(deliver.getId(), id, member_id_list, member.getId(), sType);
                }
                //处理短信数据
                handleSmsData(name, member.getMobile(), null, length, balance, content, id, member_id, deliverId, status, sType, deliverGroupId, link, deliverUrgeId);
                //如果是催答发送短信，催答次数加一
                updateDeliverGroupData(member_id, deliverGroupId, deliverId);
            }
            return;
        }
        if (flag) {
            for (String member_id : member_id_list) {
                MemberDto member = memberGrpcClient.getMemberById(member_id);
                Map<String, String> keyMap = new HashMap<>(dto.getKwargs());
                if (Objects.isNull(member)) {
                    log.error("[deliver]短信投放 executeDeliverSmsAsync member_id={} 不存在", member_id);
                    continue;
                }
                Group group = null;
                String code = "";
                if (StrUtil.isNotEmpty(member.getStore())) {
                    //此处相同的store可优化成缓存
                    group = userGrpcClient.getGroup(member.getStore());
                    if (Objects.isNull(group)) {
                        log.error(String.format("SmsDeliver getGroup[id=%s] not found", member.getStore()));
                        continue;
                    }
                    code = group.getCode();
                }
                String mobile = member.getMobile();
                keyMap.put("code", code);
                keyMap.put("memberId", member_id);
                if (checkSubmitFlag) {
                    keyMap.put("checkCode", member_id);
                }
                String link = getSurveySmsDwzUrl(dto.getOrgId(), dto.getSurveyId(), deliverId, checkSubmitFlag, keyMap);
                //投放时插入字段
                String name = Optional.ofNullable(member.getName()).orElse("");
                if (name.length() > 8) {
                    name = name.substring(0, 8);
                }
                String storeName = Optional.ofNullable(group).map(Group::getName).orElse("");
                if (storeName.length() > 10) {
                    storeName = storeName.substring(0, 10);
                }
                //替换模板内容, 需要替换字段,问卷名称10,项目名称10,系统名称：取个性化设置中的系统名称15,联系人姓名8,联系人所属组织10,问卷链接 28
                String content = handleSmsContent(dto.getTemplate(), projectName, name, storeName, quesName, systemName, link);

                if (StringUtils.isEmpty(sign)) {
                    sign = "【倍市得CEM】";
                }

                String msgid = null;
                Integer status = null;
                int length;
                double balance;
                if (dto.getNoDisturbMemberIdlist().contains(member.getId())) {
                    //免打扰时不走投放 状态为免打扰拦截
                    msgid = genDeliverMsgid(null);
                    status = SMSRECORD_STATUS_DISTRUB.getNumber();
                    link = "";
                    length = 1;
                    balance = 0.0;
                } else if (Objects.equals(member.getMemberDeliveryStatus(), MEMBER_DELIVERY_STATUS_DISABLED.getValue())) {
                    //黑名单拦截，不进行投放
                    msgid = genDeliverMsgid(null);
                    status = SmsRecordStatusEnum.SMSRECORD_STATUS_MEMBER_BLACKLIST.getValue();
                    link = "";
                    length = 1;
                    balance = 0.0;
                } else {
                    //如果开启不发送短信，直接返回
                    if (smsNotSend) {
                        msgid = genDeliverMsgid("test");
                        length = 1;
                        balance = 0.0;
                    } else {
                        if (StrUtil.isEmpty(link)) {
                            //没有投放链接时抛出异常并记录投放失败
                            throw new BusinessException("-1", "投放时未生成url");
                        }
                        try {
                            //发送短信
                            //Map<String, Object> keywards = new HashMap<>();
                            //if (StrUtil.equals("push", smsType)) {
                            //    keywards.put("component_code", getSmsHelper(orgId));
                            //    keywards.put("sign", sign);
                            //}
                            Map<String, Object> res = smsService.sendSms(member.getMobile(), content, null);
                            length = (Integer) Optional.ofNullable(res.get("length")).orElse(0);
                            balance = (Double) Optional.ofNullable(res.get("balance")).orElse(0.0);
                            if (!ObjectUtils.isEmpty(res.get("content"))) {
                                content = (String) res.get("content");
                            }
                            //msgid = (String) res.getOrDefault("msg_id", "");
                            status = SMSRECORD_STATUS_SUCCESS.getNumber();
                        } catch (Exception e) {
                            //发送异常时添加记录发送失败
                            status = SMSRECORD_STATUS_FAILED.getNumber();
                            //msgid = genDeliverMsgid(null);
                            length = 1;
                            balance = 0.0;
                            log.error("短信[{}]发送失败", member.getMobile(), e);
                        }
                    }
                }
                //处理短信数据
                handleSmsData(name, mobile, null, length, balance, content, id, member_id, deliverId, status, sType, deliverGroupId, link, deliverUrgeId);
                createDeliverGroupData(ListUtil.of(member_id), deliverGroupId, deliverId);
            }
        } else {
            //没有投放链接时抛出异常并记录投放失败,则要 直接用手机号或者邮箱投放
            List<String> mobileList = dto.getMobileList();
            for (String mobile : mobileList) {
                Map<String, String> keyMap = new HashMap<>(dto.getKwargs());
                if (checkSubmitFlag) {
                    keyMap.put("checkCode", mobile);
                }
                keyMap.put("mobile", mobile);
                String link = getSurveySmsDwzUrl(dto.getOrgId(), dto.getSurveyId(), dto.getDeliverId(), checkSubmitFlag, keyMap);
                List<String> contacts = dto.getSmsContacts().get(mobile);
                //投放时插入字段
                String name = contacts.get(0);
                String storeName = contacts.get(1);
                //替换模板内容, 需要替换字段,问卷名称10,项目名称10,系统名称：取个性化设置中的系统名称15,联系人姓名8,联系人所属组织10,问卷链接 28
                String content = handleSmsContent(dto.getTemplate(), projectName, name, storeName, quesName, systemName, link);

                if (StringUtils.isEmpty(sign)) {
                    sign = "【倍市得CEM】";
                }

                if (StrUtil.isEmpty(link)) {
                    //没有投放链接时抛出异常并记录投放失败
                    throw new BusinessException("-1", "投放时未生成url");
                }
                //String msgid = null;
                Integer status = null;
                int length;
                double balance;
                //如果开启不发送短信，直接返回
                if (smsNotSend) {
                    //msgid = genDeliverMsgid("test");
                    length = 1;
                    balance = 0.0;
                } else {
                    if (StrUtil.isEmpty(link)) {
                        //没有投放链接时抛出异常并记录投放失败
                        throw new BusinessException("-1", "投放时未生成url");
                    }
                    try {
                        //发送短信
                        //Map<String, Object> keywards = new HashMap<>();
                        //if (StrUtil.equals("push", smsType)) {
                        //    keywards.put("component_code", getSmsHelper(orgId));
                        //    keywards.put("sign", sign);
                        //}
                        Map<String, Object> res = smsService.sendSms(mobile, content, null);
                        length = (Integer) Optional.ofNullable(res.get("length")).orElse(0);
                        balance = (Double) Optional.ofNullable(res.get("balance")).orElse(0.0);
                        if (!ObjectUtils.isEmpty(res.get("content"))) {
                            content = (String) res.get("content");
                        }
                        //msgid = (String) res.getOrDefault("msg_id", "");
                        status = SMSRECORD_STATUS_SUCCESS.getNumber();
                    } catch (Exception e) {
                        //发送异常时添加记录发送失败
                        status = SMSRECORD_STATUS_FAILED.getNumber();
                        //msgid = genDeliverMsgid(null);
                        length = 1;
                        balance = 0.0;
                        log.error("短信[{}]发送失败", mobile, e);
                    }
                }
                //处理短信数据
                handleSmsData(name, mobile, null, length, balance, content, id, null, deliverId, status, sType, deliverGroupId, link, deliverUrgeId);
                //createDeliverGroupData(ListUtil.of(member_id), deliverGroupId, deliverId);
            }
        }

        //此处没有加锁，可能会出现并发问题
        Integer msgTotal = dto.getMsgTotal();
        String lkey = "deliver:sms_deliver_done_msg_count:" + dto.getDeliverId();
        Long increment = redisService.incr(lkey);
        log.info("[deliver]短信投放完成消费,deliverid：{},批次：{},本次处理数量：{}", dto.getDeliverId(), increment, member_id_list.size());
        if (Objects.nonNull(increment) && increment == 1L) {
            redisService.expire(lkey, 24, TimeUnit.HOURS);
        }
        //最后消费完成的，更新状态
        if (Objects.nonNull(increment) && msgTotal == increment.intValue()) {
            LocalDateTime deliverTime = LocalDateTime.now();
            //ds_deliver_wechatmpdeliver
            DeliverSmsDeliver updatemp = new DeliverSmsDeliver();
            updatemp.setId(dto.getId());
            updatemp.setDeliverTime(deliverTime);
            //updatemp.setUpdatedId(SecurityContextHolder.getUserId());
            smsDeliverMapper.updateById(updatemp);

            //修改投放状态，已投放
            deliver = new DeliverDeliver();
            deliver.setId(dto.getDeliverId());
            //update.setUpdatedId(SecurityContextHolder.getUserId());
            deliver.setStatus(DELIVER_STATUS_DONE.getValue());
            deliver.setDeliverTime(deliverTime);
            deliverMapper.updateById(deliver);
            log.info("[deliver]短信投放全部完成消费,deliverid：{}", dto.getDeliverId());
            redisService.del(lkey);
        }
    }

    /**
     * 将发送异常的联系人后的催答记录加入到数据库
     *
     * @param deliverId
     * @param id
     * @param member_id_list
     * @param fail_member_id
     * @param sType
     */
    private void addSmsUrgeRecord(String deliverId, String id, List<String> member_id_list, String fail_member_id, Integer sType) {
        int index = member_id_list.indexOf(fail_member_id);
        index = Math.max(index, 0);
        List<DeliverSmsRecord> recordList = new ArrayList<>(member_id_list.size() - index - 1);
        DeliverSmsRecord record = new DeliverSmsRecord();
        record.setContent("send msg error");
        record.setBalance(0.0);
        record.setSmsDeliverId(id);
        record.setDeliverId(deliverId);
        record.setSType(sType);
        for (int i = index; i < member_id_list.size(); i++) {
            String member_id = member_id_list.get(index);
            MemberDto member = memberGrpcClient.getMemberById(member_id);
            if (Objects.isNull(member)) {
                continue;
            }
            DeliverSmsRecord newRecord = new DeliverSmsRecord();
            BeanUtil.copyProperties(record, newRecord);
            newRecord.setUsername(member.getName());
            newRecord.setPhone(member.getMobile());
            newRecord.setMemberId(member_id);
            recordList.add(newRecord);
        }
        smsRecordMapper.insertBatchSomeColumn(recordList);
    }

    /**
     * push服务发送短信要这个玩意
     */
    private String getSmsHelper(String orgId) {
        DeliverSmsBalance smsbalance = getSmsbalanceByOrgID(orgId);
        Objects.requireNonNull(smsbalance, "初始化ds_deliver_smsbalance未执行");
        return smsbalance.getCode();
    }

    private String getSignByOrg(String orgId) {
        DeliverSmsBalance sms_balance = getSmsbalanceByOrgID(orgId);
        Objects.requireNonNull(sms_balance, "初始化ds_deliver_smsbalance未执行");
        return sms_balance.getSignature();
    }

    private DeliverSmsBalance getSmsbalanceByOrgID(String orgId) {
        LambdaQueryWrapper<DeliverSmsBalance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverSmsBalance::getOrgId, orgId);
        queryWrapper.last("limit 1");
        DeliverSmsBalance deliverSmsBalance = deliverSmsBalanceMapper.selectOne(queryWrapper);
        if (deliverSmsBalance != null) {
            return deliverSmsBalance;
        } else {
            log.error("这里的逻辑挪到(GET)/api/deliver/balance/接口初始化了");
            //这里的逻辑挪到get /api/deliver/balance/ 这个接口初始化了
            return null;
        }
    }

    private void handleSmsData(String name, String mobile, String msgid, Integer length, Double balance, String content, String id, String member_id, String deliverId, Integer status, Integer sType, String deliverGroupId, String link, String deliverUrgeId) {
        DeliverSmsRecord record = new DeliverSmsRecord();
        record.setPhone(mobile);
        //record.setMsgid(msgid);
        record.setContent(content);
        Map<String, String> paramsMap = new HashMap<>(2);
        paramsMap.put("surveylink", link);
        record.setParams(JSON.toJSONString(paramsMap));
        record.setLength(length);
        record.setBalance(balance);
        record.setSmsDeliverId(id);
        record.setDeliverId(deliverId);
        record.setStatus(status);
        record.setSType(sType);
        if (StringUtils.isNotEmpty(deliverGroupId)) {
            record.setDeliverGroupId(deliverGroupId);
        }
        if (StringUtils.isNotEmpty(member_id)) {
            record.setUsername(name);
            record.setMemberId(member_id);
            //可以优化成批量
            //createDeliverGroupData(ListUtil.of(member_id), deliverGroupId, deliverId);
        }
        record.setDeliverUrgeId(deliverUrgeId);
        smsRecordMapper.insert(record);
    }

    private void handleEmailData(String name, String email, String msgid, String content, String id, String member_id, String deliverId, Integer status, Integer sType, String deliverGroupId, String link) {
        DeliverEmailRecord record = new DeliverEmailRecord();
        record.setEmail(email);
        //record.setMsgid(msgid);
        record.setContent(content);
        Map<String, String> paramsMap = new HashMap<>(2);
        paramsMap.put("surveylink", link);
        record.setParams(JSON.toJSONString(paramsMap));
        record.setEmailDeliverId(id);
        record.setDeliverId(deliverId);
        record.setStatus(status);
        record.setSType(sType);
        if (StringUtils.isNotEmpty(deliverGroupId)) {
            record.setDeliverGroupId(deliverGroupId);
        }
        if (StringUtils.isNotEmpty(member_id)) {
            record.setUsername(name);
            record.setMemberId(member_id);
            //可以优化成批量
            //createDeliverGroupData(ListUtil.of(member_id), deliverGroupId, deliverId);
        }
        emailRecordMapper.insert(record);
    }

    private JSONObject sendEmail(String emailTo, String subject, String content, String mailFrom, String smtpId, String id) {
        //String msgid;
        int status;
        try {
            if (StrUtil.isNotEmpty(smtpId)) {
                /*Smtp userSmtp = userGrpcClient.getUserSmtpById(smtpId);
                if (Objects.nonNull(userSmtp) && SMTP_VALIDATE_STATUS_VERIFYSUCCESS.equals(userSmtp.getStatus().getNumber())) {
                    return sendEmailEnd(emailTo, subject, content, userSmtp.getAccount(), null, id);
                }*/
                mailService.sendEmail(Collections.singletonList(emailTo), null, subject, content, smtpId, null);
            }
            //正常发送
            //msgid = String.valueOf(task_number);
            status = EMAILRECORD_STATUS_SUCCESS.getValue();
        } catch (Exception e) {
            //发送异常时添加记录发送失败
            //msgid = genDeliverMsgid(null);
            status = EMAILRECORD_STATUS_FAILED.getValue();
        }
        JSONObject res = new JSONObject();
        //res.put("msgid", msgid);
        res.put("status", status);
        return res;
    }


    private String handleEmailSubjectAndContent(String value, String projectName, String name, String storeName, String quesName, String systemName, String emailTime, String link, boolean isContent) {
        //邮件中插入的字段为a标签的超链接
        String survey_link = "<a style='color:#2672ff' href='{corp_url}' target='_blank'>{input_content}</a>";
        if (value.contains("${问卷链接=")) {
            Matcher matcher = P_PATTERN_EMAIL.matcher(value);
            while (matcher.find()) {
                String v = matcher.group();
                //问卷链接内容只取前十位
                String linkContent = v.substring(v.indexOf("\"") + 1, v.lastIndexOf("\""));
                linkContent = linkContent.length() > 10 ? linkContent.substring(0, 10) : linkContent;
                value = value.replace(v, isContent ? survey_link.replace("{corp_url}", link).replace("{input_content}", linkContent)
                        : linkContent + link);
            }
        }
        return value.replaceAll("\\$\\{问卷链接}", link)
                .replaceAll("\\$\\{项目名称}", projectName)
                .replaceAll("\\$\\{联系人姓名}", name)
                .replaceAll("\\$\\{联系人所属组织}", storeName)
                .replaceAll("\\$\\{问卷名称}", quesName)
                .replaceAll("\\$\\{系统名称}", systemName)
                .replaceAll("\\$\\{发邮件日期}", emailTime);
    }

    private String handleSmsContent(String value, String projectName, String name, String storeName, String quesName, String systemName, String link) {
        return value.replaceAll("\\$\\{问卷链接}", link)
                .replaceAll("\\$\\{项目名称}", projectName)
                .replaceAll("\\$\\{联系人姓名}", name)
                .replaceAll("\\$\\{联系人所属组织}", storeName)
                .replaceAll("\\$\\{问卷名称}", quesName)
                .replaceAll("\\$\\{系统名称}", systemName);
    }


    private String getSurveyEmailDwzUrl(String orgId, String surveyId, String deliverId, boolean checkSubmitFlag, Map<String, String> kwargs) {
        OrgInfoDto org = userGrpcClient.getOrganization(orgId);
        kwargs.put("source", String.valueOf(RESPONDENT_SOURCE_EMAIL.getNumber()));
        kwargs.put("scenes", String.valueOf(DELIVER_SCENES_TIMING.getValue()));
        kwargs.put("checkSubmit", checkSubmitFlag ? "1" : "0");
        JSONObject surveyLink = deliverDeliverService.getSurveyLink(orgId, surveyId, deliverId, org.getCode(), kwargs);
        String url = surveyLink.getString("url");
        String domain = surveyLink.getString("domain");
        return deliverDeliverService.getSurveyDwzLink(url, domain);
    }

    private String getSurveySmsDwzUrl(String orgId, String surveyId, String deliverId, boolean checkSubmitFlag, Map<String, String> kwargs) {
        OrgInfoDto org = userGrpcClient.getOrganization(orgId);
        kwargs.put("source", String.valueOf(RESPONDENT_SOURCE_SMS.getNumber()));
        kwargs.put("scenes", String.valueOf(DELIVER_SCENES_TIMING.getValue()));
        kwargs.put("checkSubmit", checkSubmitFlag ? "1" : "0");
        JSONObject surveyLink = deliverDeliverService.getSurveyLink(orgId, surveyId, deliverId, org.getCode(), kwargs);
        String url = surveyLink.getString("url");
        String domain = surveyLink.getString("domain");
        return deliverDeliverService.getSurveyDwzLink(url, domain);
    }

    /**
     * 通过member_id、org_id获取sig用于邮件订阅/退订链接参数拼接
     */
    /*private String getEmailSubscribeSig(String member_id, String orgId) {
        String member_sig;
        String org_sig;
        try {
            member_sig = memberGrpcClient.genMemberSig(member_id);
            org_sig = memberGrpcClient.genOrgSig(orgId);
        } catch (Exception e) {
            member_sig = "";
            org_sig = "";
        }
        JSONObject res = new JSONObject();
        res.put("member_id", member_id);
        res.put("member_sig", Optional.ofNullable(member_sig).orElse(""));
        res.put("org_id", orgId);
        res.put("org_sig", org_sig);
        log.info("参数：{}", res.toJSONString());
        return URLEncoder.encode(res.toJSONString());
    }*/
    private void userGroupTitleModify(String orgId, String oldTitle, String newTitle) {
        // 更加层级组织节点的title数据变化更新默认投放链接的名称
        // 更新surveyRegion中的title
        surveyRegionMapper.update(null, new LambdaUpdateWrapper<DeliverSurveyRegion>()
                .eq(DeliverSurveyRegion::getOrgId, orgId).eq(DeliverSurveyRegion::getTitle, oldTitle)
                .set(DeliverSurveyRegion::getTitle, newTitle));
        // 更新DefaultDeliverStore中的title
        deliverDefaultDeliverStoreMapper.update(null, new LambdaUpdateWrapper<DeliverDefaultDeliverStore>()
                .eq(DeliverDefaultDeliverStore::getOrgId, orgId).eq(DeliverDefaultDeliverStore::getTitle, oldTitle)
                .set(DeliverDefaultDeliverStore::getTitle, newTitle));
    }

    private void createDefaultStoreWithInfo(String orgId, String projectId, String code, String title, String groupId) {
        // 创建对象时同步创建对应二维码
        DeliverDefaultDeliverStore deliverStore = deliverDefaultDeliverStoreMapper
                .selectOne(new LambdaQueryWrapper<DeliverDefaultDeliverStore>()
                        .eq(DeliverDefaultDeliverStore::getSurveyId, projectId).last("limit 1"));
        if (deliverStore == null) {
            return;
        }
        Map<String, String> newKeyMap = new HashMap<>();
        newKeyMap.put("code", code);
        String link = deliverDeliverService.getSurveyGroupDwzUrl(orgId, projectId, deliverStore.getDeliverId(), newKeyMap);
        String fileName = CommonUtil.fileNameFormat(code + "@" + title + ".png");
        deliverDeliverService.createSurveyGroupQrcodes(orgId, projectId,
                deliverStore.getDeliverId(), link, fileName, false);
        DeliverDefaultDeliverStore defaultDeliver = new DeliverDefaultDeliverStore();
        defaultDeliver.setOrgId(orgId);
        defaultDeliver.setDeliverId(deliverStore.getDeliverId());
        defaultDeliver.setRootGroupId(deliverStore.getRootGroupId());
        defaultDeliver.setGroupId(groupId);
        defaultDeliver.setCode(code);
        defaultDeliver.setTitle(title);
        defaultDeliver.setSurveyId(projectId);
        defaultDeliver.setStatus(DEFAULTDELIVERSTORE_STATUS_ACTIVATE.getNumber());
        defaultDeliver.setTtype(DEFAULTDELIVERSTORE_TTYPE_STORE.getNumber());
        defaultDeliver.setLink(link);
        defaultDeliver.setDisable(0);
        deliverDefaultDeliverStoreMapper.insert(defaultDeliver);
    }

    @Override
    public void surveyRespondentSync(JSONObject data) {
        log.info("订阅同步缓存mq");
        deliverSurveyRespondentSubmit(data);
    }
}
